package com.tianji.remark.service.impl;

import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.remark.dto.LikeRecordFormDTO;
import com.tianji.remark.dto.LikedTimesDTO;
import com.tianji.remark.entity.LikedRecord;
import com.tianji.remark.keyUtils;
import com.tianji.remark.mapper.LikedRecordMapper;
import com.tianji.remark.service.ILikedRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.tianji.common.constants.MqConstants.Exchange.LIKE_RECORD_EXCHANGE;
import static com.tianji.common.constants.MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-06-01
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LikedRecordServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {

    private final StringRedisTemplate redisTemplate;

    private final RabbitMqHelper mqHelper;
    /**
     * 点赞或取消点赞
     *
     * @param dto
     */
    @Override
    public void addLikeRecord(LikeRecordFormDTO dto) {
        //使用redis中set集合存储点赞记录： key：业务主体id 列表：用户id
        // 1.基于前端的参数，判断是执行点赞还是取消点赞
        String key = StringUtils.format(keyUtils.REMARK_SET,dto.getBizId());
        Long userId = UserContext.getUser();
        //2.执行redis add/rem操作
        boolean success = dto.getLiked() ? like(userId,key) : unlike(userId,key);
        if(!success){
            //2.1执行失败直接退出
            log.debug("重复点赞");
            return;
        }
        //3.执行成功更新点赞数
        Long size = redisTemplate.opsForSet().size(key);
        if (size == null) {
            return;
        }
        //4.点赞数缓存值zset集合中，大key：业务类型  小key：业务主体id  value：点赞数
        String zsetkey = StringUtils.format(keyUtils.REMARK_ZSET,dto.getBizType());
        redisTemplate.opsForZSet()
                .add(zsetkey,dto.getBizId().toString(),size);
    }

    /**
     * 定时任务：前往redis拉取点赞数，并发送MQ消息
     *
     * @param bizType
     * @param maxBizSize
     */
    @Override
    public void readLikedTimesAndSendMessage(String bizType, int maxBizSize) {
        //1.组装key
        String zsetkey = StringUtils.format(keyUtils.REMARK_ZSET,bizType);
        //2.往redis拉取数据
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(zsetkey, maxBizSize);
        if (typedTuples == null || typedTuples.isEmpty()) {
            return;
        }
        //3.组装List集合
        List<LikedTimesDTO> list = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            Double num = tuple.getScore();
            String key = tuple.getValue();
            if (num == null || key == null) {
                continue;
            }
            list.add(LikedTimesDTO.of(Long.valueOf(key), num.intValue()));
        }
        //4.发送MQ消息
        log.info("更新点赞数：{}",list);
        mqHelper.send(
                LIKE_RECORD_EXCHANGE,
                StringUtils.format(LIKED_TIMES_KEY_TEMPLATE, bizType),
                list);
    }

    private boolean like(Long userId, String key) {
        //2.set数据，key：业务主体id 列表：用户id
        Long result = redisTemplate.opsForSet().add(key, userId.toString());
        return result != null && result > 0;
    }

    private boolean unlike(Long userId, String key) {
        //2.set数据，key：业务主体id 列表：用户id
        Long result = redisTemplate.opsForSet().remove(key, userId.toString());
        return result != null && result > 0;
    }

}
